package view.displayManagers;

import java.awt.Color;
import java.awt.Point;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.ImageIcon;
import javax.swing.JButton;

import model.Board;
import controller.ComputerControlledGame;
import controller.GameManager;

/**
 * Class implements a display manager for automatic game mode
 */
public class SpecialGameDisplayTool extends GameDisplayTool implements SpecialGameDisplayMngr {
	
	// members
	private ComputerControlledGame gameManager; // game manager
	private ClickedPiece buttonsToUpdate; // holds data about buttons that should be updated
	private List<Point> collidingCreatures; // holds positions of colliding Creatures
	private InputOutputMngr ioManager; // manages notifications for the user
	private AtomicBoolean keepPlaying; // indicates if should keep running the game

	public GameManager getGameManager() { // TODO DEBUG!!!
		return (GameManager)gameManager;
	}

	public SpecialGameDisplayTool(Map<String, ImageIcon> iconMap, Color light, Color dark, int boardSize, ComputerControlledGame gameManager, List<JButton> boardButtons, Board gameBoard) {
		
		// initialize members using base class constructor
		super(iconMap, light, dark, boardSize, boardButtons, gameBoard);
		
		// set game manager
		this.gameManager = gameManager;
		
		// allocate last-to-be clicked button
		buttonsToUpdate = new ClickedPiece(null);
		
		// initialize colliding Creatures list
		collidingCreatures = new LinkedList<Point>();
		
		// allocate input-output manager
		this.ioManager = new ContactUser();
		
		// initialize running indicator
		keepPlaying = new AtomicBoolean(true);
	}

	/**
	 * Setting the board buttons in computer-controlled game requires no action listeners
	 */
	@Override
	public List<JButton> setButtons(List<JButton> buttons) {
		
		// no listeners to attach
		return buttons;
	}

	/**
	 * Sets the board with two-players layout
	 */
	@Override
	public void setBoard() {

		// set standard board for two players
		gameManager.setTowPlayersBoard();
	}
	
	/**
	 * Updates changes in the game board display.
	 * Piece positions are updated using base class's method.
	 * Function updates Creature positions and the position of a Creature that destroyed a piece 
	 * @param prevCreaturePositions- Creatures' positions from previous turn
	 * @param currCreaturePositions- Creatures' positions of current turn
	 * @param destroyerCreature- position of Creature that has destroyed a piece
	 */
	public void refreshBoardDisplay(List<Point> prevCreaturePositions, List<Point> currCreaturePositions, Point destroyerCreature) {
		
		// clear the collection of colliding Creatures' positions
		collidingCreatures.clear();
		
		// get board size
		int boardSize = super.getBoardSize();
		
		// get board buttons icons
		Map<String, ImageIcon> iconMap = super.getIconMap();
		
		// get board buttons
		List<JButton> buttons = super.getBoardButtons();
		
		// update icon of positions that do not hold Creatures any more
		for (Point currPosition : prevCreaturePositions) {
			
			// check if Creature have collided at this position
			if (!currCreaturePositions.contains(currPosition)) {
				
				// get button matching current position on board
				int index = (currPosition.x-1)*boardSize + currPosition.y-1; // convert row-column index to linear index
				JButton currBtn = buttons.get(index);
				
				// set button's icon
				currBtn.setIcon(iconMap.get("creature-collide"));
				
				// TODO clear button's icon during next refresh 
				collidingCreatures.add(currPosition);
			}
		}
		
		// update icon of Creatures' positions
		for (Point currPosition : currCreaturePositions) {
				
			// get button matching current position on board
			int index = (currPosition.x-1)*boardSize + currPosition.y-1; // convert row-column index to linear index
			JButton currBtn = buttons.get(index);
			
			// set button's icon
			currBtn.setIcon(iconMap.get("creature"));
		}
		
		// refresh positions that are not related to Creatures
		super.refreshBoardDisplay(buttonsToUpdate);
		
		// check if a piece was destroyed by a Creature
		if (destroyerCreature != null) {
			
			// update icon of the destroyer Creature
			
			// get button matching current position on board
			int index = (destroyerCreature.x-1)*boardSize + destroyerCreature.y-1; // convert row-column index to linear index
			JButton currBtn = buttons.get(index);
			
			// set button's icon
			currBtn.setIcon(iconMap.get("creature-attack"));
		}
 
	}
	
	/**
	 * 
	 */
	@Override
	public void refreshBoardDisplay() {
		super.refreshBoardDisplay(buttonsToUpdate); // TODO
	}

	/**
	 * Runs the special game, until reached given maximal turns number or checkmate.
	 * Each turn lasts the given amount of time
	 */
	@Override
	public void runSpecialGame(int maxTurns, int turnDuration, int interval) {

		// allow the game to run
		keepPlaying.set(true);
		
		// get reference to auto-game display tool
		final SpecialGameDisplayTool displayTool = this;

		// set delay time for display refresh
		final int delay = turnDuration;
		
		// set bound for turn number
		final int turnNumberBound = maxTurns;
		
		// allocate a new timer
		Timer timer = new Timer();
		
		TimerTask timerTask = new TimerTask() {
			 
			// count how many turns were played
			private int turnCounter = 0;
			
			// allocate list for Creature positions
			List<Point> prevCreaturePositions = new LinkedList<Point>();
			List<Point> currCreaturePositions = new LinkedList<Point>();
			
			@Override
			public void run() {
				
				// keep playing until game over or force stop
				while (keepPlaying.get()) {
				
					Point destroyerCreature = null;
					
					// place creatures on board
					currCreaturePositions = gameManager.placeCreatures(); 
					
					// display Creatures
					buttonsToUpdate.getMoveList().clear();
					buttonsToUpdate.getMoveList().addAll(collidingCreatures);
					displayTool.refreshBoardDisplay(prevCreaturePositions, currCreaturePositions, destroyerCreature);
					
					// make automatic move
					Point[] pointVec = gameManager.makeMoveComputerSpecialGame(); // TODO variable name				
					Point srcPosition = pointVec[0];
					Point destPosition = pointVec[1];
					destroyerCreature = pointVec[2];
					
					// update positions to change on board
					buttonsToUpdate.getMoveList().clear();
					buttonsToUpdate.getMoveList().add(srcPosition);
					buttonsToUpdate.getMoveList().add(destPosition);
					
					// increment turn counter
					++turnCounter;
					
					// refresh game board display
					displayTool.refreshBoardDisplay(prevCreaturePositions, currCreaturePositions, destroyerCreature);
					
					// delay the display
					try {
						Thread.sleep(delay);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					// check if game was stopped during the sleep
					if (!keepPlaying.get()) {
						return;
					}
					
					// update list of Creatures' previous positions
					prevCreaturePositions.clear();
					prevCreaturePositions.addAll(currCreaturePositions);
			
					// check if game is over
					
					if (turnCounter >= turnNumberBound) { // check if ends due to number of turns played
						
						// update board display
						displayTool.refreshBoardDisplay(prevCreaturePositions, currCreaturePositions, destroyerCreature);
						
						// stop game
						keepPlaying.set(false);
						cancel();
						
						// notify user
						gameOver("Game over- played " + turnNumberBound + " turns");
						
					} else if (gameManager.isCheckmate()) { // check if ends due to checkmate 
						
						// update board display
						displayTool.refreshBoardDisplay(prevCreaturePositions, currCreaturePositions, destroyerCreature);
						
						// stop game
						keepPlaying.set(false);
						cancel();
						
						// notify user
						gameOver("Game over- checkmate");
						
					} else if (gameManager.isStalemate()) { // check if end due to stalemate
						
						// update board display
						displayTool.refreshBoardDisplay(prevCreaturePositions, currCreaturePositions, destroyerCreature);
						
						// stop game
						keepPlaying.set(false);
						cancel();
						
						// notify user
						gameOver("Game over- stalemate");
					}
				}
				
				((GameManager)gameManager).logger.close();
			}			 
		 };
		 
		 // run game
		 timer.schedule(timerTask, 0); // TODO use const
	}

	/**
	 * Stops currently running special game
	 */
	@Override
	public void stopSpecialGame() {
		
		// stop game
		keepPlaying.set(false);
	}

	/**
	 * Notifies user that game is in Check
	 */
	@Override
	public void notifyCheck() {
		ioManager.notifyCheck();
	}

	/**
	 * Uses the input-output manager to notify user that game is over 
	 * and to display given message
	 */
	@Override
	public void gameOver(String msg) {
		ioManager.notifyGameOver(msg);
	}

	/**
	 * Returns the default option for the piece to replace the Pawn
	 */
	@Override
	public int replacePawn(String[] options, int defualtOption) {
		return defualtOption;
	}
}